package dk.eclipse.android.badassapp.location;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import dk.eclipse.android.badassapp.distance.DistanceActivity;

import android.app.Activity;
import android.app.PendingIntent;
import android.location.Criteria;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.location.GpsStatus.Listener;
import android.location.GpsStatus.NmeaListener;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;

/**
 * @author jaw
 * 
 *         Wrap locationmanager to provide a location from the best service
 *         available. Extends service to get a handle to the locationmanager.
 * 
 */
public class MyLocationManagerImpl extends Activity implements IMyLocationManager {
	private static final String LOG_TAG = MyLocationManagerImpl.class.getSimpleName();

	private LocationManager mLocationManager;

	// Hide so this can only be created using the INSTANCE
	public MyLocationManagerImpl(LocationManager locationManager) {
		super();
		
		mLocationManager = locationManager;
		Log.d(LOG_TAG, mLocationManager.toString());
	}

	// Changed
	/*
	 * (non-Javadoc)
	 * 
	 * Return the best quality location available from the available sources.
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#getLastKnownLocation
	 * ()
	 */
	public Location getLastKnownLocation(/* String provider */) {
		// Check them all.
		List<String> mAllProviders = getAllProviders();
		List<Location> locations = new ArrayList<Location>(mAllProviders.size());
		for (Iterator iterator = mAllProviders.iterator(); iterator.hasNext();) {
			String provider = (String) iterator.next();
			if (isProviderEnabled(provider)) {
				Location lastKnownLocation = mLocationManager
						.getLastKnownLocation(provider);
				if (null != lastKnownLocation) {
					locations.add(lastKnownLocation);
				}
			}
		}

		switch (locations.size()) {
		case 0:
			return null;
		case 1:
			return locations.get(0);
		default:
			Collections.sort(locations, new Comparator<Location>() {

				@Override
				public int compare(Location object1, Location object2) {
					// Sort in ascending order
					if (object1.hasAccuracy() && object2.hasAccuracy())
						if (object1.getAccuracy() > object2.getAccuracy()) {
							return 1;
						} else if (object1.getAccuracy() < object2
								.getAccuracy()) {
							return -1;
						} else {
							return 0;
						}
					return 0;
				}
			});
			return locations.get(0);
		}
	}

	// DELEGATES BELOW
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#addGpsStatusListener
	 * (android.location.GpsStatus.Listener)
	 */
	public boolean addGpsStatusListener(Listener listener) {
		return mLocationManager.addGpsStatusListener(listener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#addNmeaListener(android
	 * .location.GpsStatus.NmeaListener)
	 */
	public boolean addNmeaListener(NmeaListener listener) {
		return mLocationManager.addNmeaListener(listener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#addProximityAlert
	 * (double, double, float, long, android.app.PendingIntent)
	 */
	public void addProximityAlert(double latitude, double longitude,
			float radius, long expiration, PendingIntent intent) {
		mLocationManager.addProximityAlert(latitude, longitude, radius,
				expiration, intent);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#addTestProvider(java
	 * .lang.String, boolean, boolean, boolean, boolean, boolean, boolean,
	 * boolean, int, int)
	 */
	public void addTestProvider(String name, boolean requiresNetwork,
			boolean requiresSatellite, boolean requiresCell,
			boolean hasMonetaryCost, boolean supportsAltitude,
			boolean supportsSpeed, boolean supportsBearing,
			int powerRequirement, int accuracy) {
		mLocationManager.addTestProvider(name, requiresNetwork,
				requiresSatellite, requiresCell, hasMonetaryCost,
				supportsAltitude, supportsSpeed, supportsBearing,
				powerRequirement, accuracy);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#clearTestProviderEnabled
	 * (java.lang.String)
	 */
	public void clearTestProviderEnabled(String provider) {
		mLocationManager.clearTestProviderEnabled(provider);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#clearTestProviderLocation
	 * (java.lang.String)
	 */
	public void clearTestProviderLocation(String provider) {
		mLocationManager.clearTestProviderLocation(provider);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#clearTestProviderStatus
	 * (java.lang.String)
	 */
	public void clearTestProviderStatus(String provider) {
		mLocationManager.clearTestProviderStatus(provider);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#equals(java.lang.
	 * Object)
	 */
	public boolean equals(Object o) {
		return mLocationManager.equals(o);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#getAllProviders()
	 */
	public List<String> getAllProviders() {
		return mLocationManager.getAllProviders();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#getBestProvider(android
	 * .location.Criteria, boolean)
	 */
	public String getBestProvider(Criteria criteria, boolean enabledOnly) {
		return mLocationManager.getBestProvider(criteria, enabledOnly);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#getGpsStatus(android
	 * .location.GpsStatus)
	 */
	public GpsStatus getGpsStatus(GpsStatus status) {
		return mLocationManager.getGpsStatus(status);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#getProvider(java.
	 * lang.String)
	 */
	public LocationProvider getProvider(String name) {
		return mLocationManager.getProvider(name);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#getProviders(boolean)
	 */
	public List<String> getProviders(boolean enabledOnly) {
		return mLocationManager.getProviders(enabledOnly);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#getProviders(android
	 * .location.Criteria, boolean)
	 */
	public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
		return mLocationManager.getProviders(criteria, enabledOnly);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see dk.eclipse.android.badassapp.tab.IMyLocationManager#hashCode()
	 */
	public int hashCode() {
		return mLocationManager.hashCode();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#isProviderEnabled
	 * (java.lang.String)
	 */
	public boolean isProviderEnabled(String provider) {
		return mLocationManager.isProviderEnabled(provider);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#removeGpsStatusListener
	 * (android.location.GpsStatus.Listener)
	 */
	public void removeGpsStatusListener(Listener listener) {
		mLocationManager.removeGpsStatusListener(listener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#removeNmeaListener
	 * (android.location.GpsStatus.NmeaListener)
	 */
	public void removeNmeaListener(NmeaListener listener) {
		mLocationManager.removeNmeaListener(listener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#removeProximityAlert
	 * (android.app.PendingIntent)
	 */
	public void removeProximityAlert(PendingIntent intent) {
		mLocationManager.removeProximityAlert(intent);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#removeTestProvider
	 * (java.lang.String)
	 */
	public void removeTestProvider(String provider) {
		mLocationManager.removeTestProvider(provider);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#removeUpdates(android
	 * .location.LocationListener)
	 */
	public void removeUpdates(LocationListener listener) {
		mLocationManager.removeUpdates(listener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#removeUpdates(android
	 * .app.PendingIntent)
	 */
	public void removeUpdates(PendingIntent intent) {
		mLocationManager.removeUpdates(intent);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#requestLocationUpdates
	 * (java.lang.String, long, float, android.location.LocationListener,
	 * android.os.Looper)
	 */
	public void requestLocationUpdates(String provider, long minTime,
			float minDistance, LocationListener listener, Looper looper) {
		mLocationManager.requestLocationUpdates(provider, minTime, minDistance,
				listener, looper);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#requestLocationUpdates
	 * (java.lang.String, long, float, android.location.LocationListener)
	 */
	public void requestLocationUpdates(String provider, long minTime,
			float minDistance, LocationListener listener) {
		mLocationManager.requestLocationUpdates(provider, minTime, minDistance,
				listener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#requestLocationUpdates
	 * (java.lang.String, long, float, android.app.PendingIntent)
	 */
	public void requestLocationUpdates(String provider, long minTime,
			float minDistance, PendingIntent intent) {
		mLocationManager.requestLocationUpdates(provider, minTime, minDistance,
				intent);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#sendExtraCommand(
	 * java.lang.String, java.lang.String, android.os.Bundle)
	 */
	public boolean sendExtraCommand(String provider, String command,
			Bundle extras) {
		return mLocationManager.sendExtraCommand(provider, command, extras);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#setTestProviderEnabled
	 * (java.lang.String, boolean)
	 */
	public void setTestProviderEnabled(String provider, boolean enabled) {
		mLocationManager.setTestProviderEnabled(provider, enabled);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#setTestProviderLocation
	 * (java.lang.String, android.location.Location)
	 */
	public void setTestProviderLocation(String provider, Location loc) {
		mLocationManager.setTestProviderLocation(provider, loc);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * dk.eclipse.android.badassapp.tab.IMyLocationManager#setTestProviderStatus
	 * (java.lang.String, int, android.os.Bundle, long)
	 */
	public void setTestProviderStatus(String provider, int status,
			Bundle extras, long updateTime) {
		mLocationManager.setTestProviderStatus(provider, status, extras,
				updateTime);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see dk.eclipse.android.badassapp.tab.IMyLocationManager#toString()
	 */
	public String toString() {
		return mLocationManager.toString();
	}

	@Override
	public Location getLastKnownLocation(String provider) {
		return mLocationManager.getLastKnownLocation(provider);
	}

}
